using Microsoft.Extensions.Options;
using System.IO.Compression;
using WebRtcProject.Models.Configuration;

namespace WebRtcProject.Services.Logging
{
    public interface ILogResourceManager
    {
        Task InitializeAsync();
        Task<long> GetCurrentLogSizeAsync();
        Task<bool> CheckMemoryUsageAsync();
        Task CleanupOldLogsAsync();
        Task<LogResourceStatus> GetResourceStatusAsync();
        void StartBackgroundCleanup();
        void StopBackgroundCleanup();
    }

    public class LogResourceManager : ILogResourceManager, IDisposable
    {
        private readonly ResourceControlOptions _options;
        private readonly ILogger<LogResourceManager> _logger;
        private readonly Timer? _cleanupTimer;
        private readonly string _logDirectory;
        private volatile bool _disposed;

        public LogResourceManager(IOptions<SerilogOptions> serilogOptions, ILogger<LogResourceManager> logger)
        {
            _options = serilogOptions.Value.ResourceControl;
            _logger = logger;
            _logDirectory = Path.GetDirectoryName(serilogOptions.Value.File.Path) ?? "logs";

            if (_options.Cleanup.AutoCleanup)
            {
                _cleanupTimer = new Timer(
                    async _ => await CleanupOldLogsAsync(),
                    null,
                    _options.Cleanup.CleanupInterval,
                    _options.Cleanup.CleanupInterval);
            }
        }

        public async Task InitializeAsync()
        {
            try
            {
                // 确保日志目录存在
                Directory.CreateDirectory(_logDirectory);
                Directory.CreateDirectory(Path.Combine(_logDirectory, "errors"));
                Directory.CreateDirectory(Path.Combine(_logDirectory, "archived"));

                _logger.LogInformation("Log resource manager initialized. Log directory: {LogDirectory}", _logDirectory);

                // 初始化时进行一次清理
                await CleanupOldLogsAsync();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to initialize log resource manager");
                throw;
            }
        }

        public async Task<long> GetCurrentLogSizeAsync()
        {
            try
            {
                if (!Directory.Exists(_logDirectory))
                    return 0;

                var directoryInfo = new DirectoryInfo(_logDirectory);
                var totalSize = await Task.Run(() =>
                    directoryInfo.GetFiles("*", SearchOption.AllDirectories)
                        .Where(f => IsLogFile(f.Name))
                        .Sum(f => f.Length));

                return totalSize;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to calculate current log size");
                return 0;
            }
        }

        public async Task<bool> CheckMemoryUsageAsync()
        {
            try
            {
                var process = System.Diagnostics.Process.GetCurrentProcess();
                var memoryUsageMB = process.WorkingSet64 / 1024 / 1024;

                var isWithinLimit = memoryUsageMB <= _options.MaxMemoryUsageMB;
                
                if (!isWithinLimit)
                {
                    _logger.LogWarning("Memory usage ({MemoryUsageMB} MB) exceeds limit ({MaxMemoryUsageMB} MB)",
                        memoryUsageMB, _options.MaxMemoryUsageMB);
                }

                return await Task.FromResult(isWithinLimit);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to check memory usage");
                return true; // 默认假设内存使用正常
            }
        }

        public async Task CleanupOldLogsAsync()
        {
            try
            {
                if (!Directory.Exists(_logDirectory))
                    return;

                var cutoffDate = DateTime.Now.AddDays(-_options.Cleanup.MaxLogAge);
                var totalSizeMB = await GetCurrentLogSizeAsync() / 1024 / 1024;

                _logger.LogInformation("Starting log cleanup. Current total size: {TotalSizeMB} MB, Max allowed: {MaxSizeMB} MB",
                    totalSizeMB, _options.MaxTotalLogSizeMB);

                var logFiles = new DirectoryInfo(_logDirectory)
                    .GetFiles("*", SearchOption.AllDirectories)
                    .Where(f => IsLogFile(f.Name) && f.CreationTime < cutoffDate)
                    .OrderBy(f => f.CreationTime)
                    .ToList();

                var deletedCount = 0;
                var compressedCount = 0;
                var deletedSize = 0L;

                foreach (var file in logFiles)
                {
                    try
                    {
                        if (_options.Cleanup.CompressOldLogs && ShouldCompressFile(file))
                        {
                            await CompressLogFileAsync(file);
                            compressedCount++;
                        }
                        else if (ShouldDeleteFile(file, cutoffDate) || totalSizeMB > _options.MaxTotalLogSizeMB)
                        {
                            deletedSize += file.Length;
                            file.Delete();
                            deletedCount++;
                            totalSizeMB -= file.Length / 1024 / 1024;
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.LogWarning(ex, "Failed to process log file: {FileName}", file.Name);
                    }
                }

                _logger.LogInformation("Log cleanup completed. Deleted: {DeletedCount} files ({DeletedSizeMB} MB), Compressed: {CompressedCount} files",
                    deletedCount, deletedSize / 1024 / 1024, compressedCount);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to cleanup old logs");
            }
        }

        public async Task<LogResourceStatus> GetResourceStatusAsync()
        {
            try
            {
                var totalLogSize = await GetCurrentLogSizeAsync();
                var isMemoryWithinLimit = await CheckMemoryUsageAsync();
                
                var process = System.Diagnostics.Process.GetCurrentProcess();
                var memoryUsageMB = process.WorkingSet64 / 1024 / 1024;

                return new LogResourceStatus
                {
                    TotalLogSizeMB = totalLogSize / 1024 / 1024,
                    MaxLogSizeMB = _options.MaxTotalLogSizeMB,
                    CurrentMemoryUsageMB = memoryUsageMB,
                    MaxMemoryUsageMB = _options.MaxMemoryUsageMB,
                    IsMemoryWithinLimit = isMemoryWithinLimit,
                    IsLogSizeWithinLimit = totalLogSize / 1024 / 1024 <= _options.MaxTotalLogSizeMB,
                    LogFileCount = Directory.Exists(_logDirectory) 
                        ? Directory.GetFiles(_logDirectory, "*", SearchOption.AllDirectories)
                            .Count(f => IsLogFile(Path.GetFileName(f)))
                        : 0,
                    LastCleanupTime = GetLastCleanupTime()
                };
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to get resource status");
                throw;
            }
        }

        public void StartBackgroundCleanup()
        {
            // 后台清理已在构造函数中启动
        }

        public void StopBackgroundCleanup()
        {
            _cleanupTimer?.Dispose();
        }

        private bool IsLogFile(string fileName)
        {
            var logExtensions = new[] { ".log", ".txt" };
            return logExtensions.Any(ext => fileName.EndsWith(ext, StringComparison.OrdinalIgnoreCase));
        }

        private bool ShouldCompressFile(FileInfo file)
        {
            // 压缩超过7天且大于1MB的日志文件
            return file.CreationTime < DateTime.Now.AddDays(-7) &&
                   file.Length > 1024 * 1024 &&
                   !file.Name.EndsWith(".gz", StringComparison.OrdinalIgnoreCase);
        }

        private bool ShouldDeleteFile(FileInfo file, DateTime cutoffDate)
        {
            return file.CreationTime < cutoffDate ||
                   file.Name.EndsWith(".gz", StringComparison.OrdinalIgnoreCase) && 
                   file.CreationTime < DateTime.Now.AddDays(-_options.Cleanup.MaxLogAge * 2);
        }

        private async Task CompressLogFileAsync(FileInfo file)
        {
            try
            {
                var compressedPath = Path.Combine(
                    Path.GetDirectoryName(file.FullName)!,
                    "archived",
                    file.Name + ".gz");

                Directory.CreateDirectory(Path.GetDirectoryName(compressedPath)!);

                using var originalFileStream = file.OpenRead();
                using var compressedFileStream = File.Create(compressedPath);
                using var compressionStream = new GZipStream(compressedFileStream, CompressionLevel.Optimal);

                await originalFileStream.CopyToAsync(compressionStream);
                
                // 删除原文件
                file.Delete();

                _logger.LogDebug("Compressed log file: {OriginalFile} -> {CompressedFile}", 
                    file.Name, Path.GetFileName(compressedPath));
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to compress log file: {FileName}", file.Name);
                throw;
            }
        }

        private DateTime? GetLastCleanupTime()
        {
            try
            {
                var cleanupMarkerFile = Path.Combine(_logDirectory, ".last_cleanup");
                if (File.Exists(cleanupMarkerFile))
                {
                    var content = File.ReadAllText(cleanupMarkerFile);
                    if (DateTime.TryParse(content, out var lastCleanup))
                        return lastCleanup;
                }

                // 更新清理标记
                File.WriteAllText(cleanupMarkerFile, DateTime.Now.ToString("O"));
                return DateTime.Now;
            }
            catch
            {
                return null;
            }
        }

        public void Dispose()
        {
            if (_disposed) return;
            _disposed = true;

            try
            {
                _cleanupTimer?.Dispose();
                _logger.LogInformation("Log resource manager disposed");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error disposing LogResourceManager: {ex.Message}");
            }
        }
    }

    public class LogResourceStatus
    {
        public long TotalLogSizeMB { get; set; }
        public long MaxLogSizeMB { get; set; }
        public long CurrentMemoryUsageMB { get; set; }
        public long MaxMemoryUsageMB { get; set; }
        public bool IsMemoryWithinLimit { get; set; }
        public bool IsLogSizeWithinLimit { get; set; }
        public int LogFileCount { get; set; }
        public DateTime? LastCleanupTime { get; set; }
        
        public double MemoryUsagePercentage => MaxMemoryUsageMB > 0 
            ? (double)CurrentMemoryUsageMB / MaxMemoryUsageMB * 100 
            : 0;
            
        public double LogSizeUsagePercentage => MaxLogSizeMB > 0 
            ? (double)TotalLogSizeMB / MaxLogSizeMB * 100 
            : 0;
    }
} 